home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_400 / 422_02 / misc / asm86.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-03-20  |  37.5 KB  |  1,407 lines

  1. /* MICRO 8086 ASSEMBLER:
  2.  
  3.     This a simple 8086 assembler which is kinda novel in that It supports
  4. a "motorola" style syntax (instead of "intel"). I plan to eventually write
  5. a companion linker, and thereby remove the requirement for MASM in the PC
  6. implementation of MICRO-C. However.... time is short and rather than keep
  7. it on the shelf.... Here it is as a "demo" program.
  8.  
  9.     I have not yet decided on an object file format, so this incarnation of
  10. the assembler simply outputs the binary code generated to a ".COM" file. If
  11. you perform an "ORG $100" at the beginning of your program, this COM file will
  12. be directly execeutable on the IBM PC (Entry point is the beginning.. $100).
  13.  
  14.     You can also implement your own output routines for whatever format you
  15. desire. That section of code is clearly marked in the source.
  16.  
  17. -    Syntax of command: ASM86 <filename> [-C -F -Q -S -T]
  18.         Reads:    <filename>.ASM        Assembler source input
  19.         Writes:    <filename>.COM        Binary output file
  20.                 <filename>.LST        Listing file
  21.         Switch:    +C        Case sensitive assembly *
  22.                 +F        Full listing, otherwise, only errors are shown
  23.                 +Q        Quiet... Inhibit progress messages
  24.                 +S        Include sorted symbol table in listing
  25.                 +T        Send listing to TTY (console), instead of .LST file
  26.         * Note: When using Case sensitive assembly, the register names
  27.                 must be entered in UPPER case.
  28.  
  29. -    Any lines beginning with ';' or '*' (in column 1) are considered to
  30.     be comments, and are ignored by the assembler.
  31.  
  32. -    Any symbol found in column one is determined to be a LABEL, no special
  33.     characters (such as ':') are used. Only labels may begin in column one,
  34.     and there must be at least one space or tab between the label and the
  35.     instruction.
  36.  
  37. -    Operands to instructions may not contain any spaces except for
  38.     those found in strings and character constants:
  39.         MOV        AX,BX        This is OK
  40.         MOV        AL,' '        This too is OK
  41.         MOV        AX, BX        ERROR: "Additional operands required"
  42.  
  43. -    No special character is needed before comments following instructions,
  44.     EXCEPT for the "RET" instruction, use ';' to delimit the comment if you
  45.     do not specify a stack adjust value.
  46.  
  47. -    Assembler makes no distinction between symbols and numbers, the '#'
  48.     character is used to denote IMMEDIATE values:
  49.         MOV        AX,DATA        Loads contents of variable 'DATA'
  50.         MOV        AX,#DATA    Loads address of variable 'DATA'
  51.         MOV        AX,123        Loads contents of address '123'
  52.         MOV        AX,#123        Loads value '123'
  53.  
  54. -    Symbols are used only to reference addresses, no information is recorded
  55.     as to the size of the symbol. At least one of the operands to an
  56.     instruction must contain an explicit size (8 or 16 bits). The assembler
  57.     knows the the size of the registers, and thus any instructions involving
  58.     registers will automatically use the correct size. For instructions which
  59.     do not reference registers, you can force one of the arguments to be
  60.     recognized as an 8 or 16 bit value by using the '<'    or '>' character as a
  61.     prefix:
  62.         MOV        AL,DATA        Moves 8 bits
  63.         MOV        AX,DATA        Moves 16 bits
  64.         MOV        DATA,#12    ERROR: "Size not known"
  65.         MOV        <DATA,#12    Moves 8 bits
  66.         MOV        DATA,#<12    Equivalent to above
  67.         MOV        >DATA,#12    Moves 16 bits
  68.         MOV        DATA,#>12    Equivalent to above
  69.         MOV        <DATA,#>12    ERROR: "Incompatible sizes"
  70.  
  71. -    The '>' and '<' prefix's have special meaning in JMP and CALL
  72.     instructions:
  73.         JMP        label        NEAR 16 bit RELATIVE jump
  74.         JMP        <label        NEAR 8 bit RELATIVE jump
  75.         JMP        >LABEL        NEAR INDIRECT jump
  76.         JMP        BX            NEAR Jump to address in BX
  77.         JMP        [BX]        NEAR Jump indirect through BX
  78.         JMP        SEG:LABEL    FAR DIRECT jump
  79.         JMP        SEG:>LABEL    FAR INDIRECT jump *
  80.         JMP        SEG:[BX]    FAR INDIRECT jump *
  81.     * In the last two examples, the SEG value is ignored, and
  82.       the SEGMENT:OFFSET is taken from the operand address.
  83.  
  84. -    Expression value items supported:
  85.         n        - Decimal value (0 - 65535)
  86.         %b        - Binary value (%0 - %1111111111111111)
  87.         @o        - Octal value (@0 - @177777)
  88.         $h        - Hexidecimal value ($0 - $ffff)
  89.         'cc'    - Quoted value (one or two chars)
  90.         name    - Symbol name ('A'-'Z', '0'-'9', '?', '_')
  91.         *        - Current program counter
  92.  
  93. -    Expression operators supported:
  94.         Unary:    -    Negation
  95.                 =    Swap high and low bytes
  96.                 <    Force 8 bit size
  97.                 >    Force 16 bit size
  98.         Binary:    +    Addition
  99.                 -    Subtraction
  100.                 *    Multiplication
  101.                 /    Division
  102.                 %    Modulus
  103.                 &    Logical AND
  104.                 |    Logical OR
  105.                 ^    Exclusive OR
  106.                 <    Shift left
  107.                 >    Shift right
  108.  
  109. -    Offsets to indirect accesses are specified by placing a constant
  110.     value immediatly before the opening '['. When both a BASE and an
  111.     INDEX register are involved, use '+' to indicate them:
  112.         MOV        AX,[BX]        Indirect through BX, no offset
  113.         MOV        AX,[SI]        Indirect through SI, no offset
  114.         MOV        AX,10[DI]    Indirect to DI with 10 byte offset
  115.         MOV        AX,[BP+SI]    Indirect through BP+SI, no offset
  116.         MOV        AX,5[BP+SI]    Indirect thought BP+SI, 5 byte offset
  117.         MOV        AX,[BX+10]    This MASM syntax NOT supported!!!
  118.  
  119. -    Directives supported:
  120.             ORG        <value>            Set program counter
  121.     <label>    EQU        <value>            Set a symbol value
  122.             SEG        <value>            Set output segment (0-3) *
  123.             DB        <value>[,...]    Define byte(s)
  124.             DW        <value>[,...]    Define word(s)
  125.             DRW        <value>[,...]    Define reversed word(s)
  126.             DS        <value>            Define storage (un-initialized)
  127.             STR        <d>string<d>    Define string <d>=any delimiter char.
  128.             STRZ    <d>string<d>    As above... Appends zero (NULL)
  129.             STRH    <d>string<d>    As above... Sets high bit on last char.
  130.             PUBLIC    <symbol>[,...]    Declare a symbol as public *
  131.             EXTERN    <symbol>[,...]    Declare a symbol as external *
  132.             SPACE                    Insert blank line in listing
  133.             PAGE                    Eject page
  134.             TITLE    <string>        Set listing title
  135.             NOLIST                    Disable listing output **
  136.             LIST                    Enable listing output **
  137.     *    These directives are not very useful yet...
  138.     **    LIST/NOLIST can be nested. Lines with errors are always listed.
  139.  
  140. Copyright 1990-1994 Dave Dunfield
  141. All rights reserved.
  142.  
  143. Permission granted for personal (non-commercial) use only.
  144.  
  145. Compile command: cc asm86 -fop
  146. */
  147. #include <stdio.h>
  148.  
  149. /* Fixed assembler parameters */
  150. #define    NUMREG    20        /* Number of registers defined */
  151. #define    NUMSEG    4        /* Maximum number of segments */
  152. #define    PAGSIZE    60        /* Number of lines per page */
  153. #define    SYMSIZE    15        /* Maximum length of a symbol name */
  154. #define    SYMBOLS    2000    /* Maximum number of symbols */
  155. #define    LINSIZE    100        /* Maximum size of input line */
  156.  
  157. /* Operand types */
  158. #define    REGIS    1        /* Simple register */
  159. #define    VALUE    2        /* Direct memory reference */
  160. #define    INDEX    3        /* Indexed memory reference */
  161. #define    IMMED    4        /* Immediate value */
  162.  
  163. /* Symbol flags */
  164. #define    SDUP    0x80    /* Duplicate symbol */
  165. #define    SPUB    0x40    /* Public symbol */
  166. #define    SEXT    0x20    /* External reference */
  167.  
  168. /* Instruction opcode table */
  169. #define    IDATSIZ    5        /* Number of bytes of instruction data */
  170.     unsigned char inst_table[] = {
  171.         /* Type 1 - all bytes up to 0x00 are written */
  172.         'A','A','A'+128,        1, 0x37, 0x00, 0x00, 0x00,
  173.         'A','A','D'+128,        1, 0xD5, 0x0A, 0x00, 0x00,
  174.         'A','A','M'+128,        1, 0xD4, 0x0A, 0x00, 0x00,
  175.         'A','A','S'+128,        1, 0x3F, 0x00, 0x00, 0x00,
  176.         'C','B','W'+128,        1, 0x98, 0x00, 0x00, 0x00,
  177.         'C','L','C'+128,        1, 0xF8, 0x00, 0x00, 0x00,
  178.         'C','L','D'+128,        1, 0xFC, 0x00, 0x00, 0x00,
  179.         'C','L','I'+128,        1, 0xFA, 0x00, 0x00, 0x00,
  180.         'C','M','C'+128,        1, 0xF5, 0x00, 0x00, 0x00,
  181.         'C','M','P','S','B'+128,1, 0xA6, 0x00, 0x00, 0x00,
  182.         'C','M','P','S','W'+128,1, 0xA7, 0x00, 0x00, 0x00,
  183.         'C','W','D'+128,        1, 0x99, 0x00, 0x00, 0x00,
  184.         'D','A','A'+128,        1, 0x27, 0x00, 0x00, 0x00,
  185.         'D','A','S'+128,        1, 0x2F, 0x00, 0x00, 0x00,
  186.         'H','L','T'+128,        1, 0xF4, 0x00, 0x00, 0x00,
  187.         'I','N','T','O'+128,    1, 0xCE, 0x00, 0x00, 0x00,
  188.         'I','R','E','T'+128,    1, 0xCF, 0x00, 0x00, 0x00,
  189.         'L','A','H','F'+128,    1, 0x9F, 0x00, 0x00, 0x00,
  190.         'L','O','D','S','B'+128,1, 0xAC, 0x00, 0x00, 0x00,
  191.         'L','O','D','S','W'+128,1, 0xAD, 0x00, 0x00, 0x00,
  192.         'M','O','V','S','B'+128,1, 0xA4, 0x00, 0x00, 0x00,
  193.         'M','O','V','S','W'+128,1, 0xA5, 0x00, 0x00, 0x00,
  194.         'N','O','P'+128,        1, 0x90, 0x00, 0x00, 0x00,
  195.         'P','O','P','F'+128,    1, 0x9D, 0x00, 0x00, 0x00,
  196.         'P','U','S','H','F'+128,1, 0x9C, 0x00, 0x00, 0x00,
  197.         'S','A','H','F'+128,    1, 0x9E, 0x00, 0x00, 0x00,
  198.         'S','C','A','S','B'+128,1, 0xAE, 0x00, 0x00, 0x00,
  199.         'S','C','A','S','W'+128,1, 0xAF, 0x00, 0x00, 0x00,
  200.         'S','T','C'+128,        1, 0xF9, 0x00, 0x00, 0x00,
  201.         'S','T','D'+128,        1, 0xFD, 0x00, 0x00, 0x00,
  202.         'S','T','I'+128,        1, 0xFB, 0x00, 0x00, 0x00,
  203.         'S','T','O','S','B'+128,1, 0xAA, 0x00, 0x00, 0x00,
  204.         'S','T','O','S','W'+128,1, 0xAB, 0x00, 0x00, 0x00,
  205.         'W','A','I','T'+128,    1, 0x9B, 0x00, 0x00, 0x00,
  206.         'X','L','A','T'+128,    1, 0xD7, 0x00, 0x00, 0x00,
  207.         'R','E','P'+128,        1, 0xF3, 0x00, 0x00, 0x00,
  208.         'R','E','P','Z'+128,    1, 0xF3, 0x00, 0x00, 0x00,
  209.         'R','E','P','E'+128,    1, 0xF3, 0x00, 0x00, 0x00,
  210.         'R','E','P','N','Z'+128,1, 0xF2, 0x00, 0x00, 0x00,
  211.         'R','E','P','N','E'+128,1, 0xF2, 0x00, 0x00, 0x00,
  212.         'L','O','C','K'+128,    1, 0xF0, 0x00, 0x00, 0x00,
  213.         /* Type 2 - MEM, REGIS, 16BIT */
  214.         'D','E','C'+128,        2, 0xFE, 0x01, 0x48, 0x00,
  215.         'D','I','V'+128,        2, 0xF6, 0x06, 0x00, 0x00,
  216.         'I','D','I','V'+128,    2, 0xF6, 0x07, 0x00, 0x00,
  217.         'I','M','U','L'+128,    2, 0xF6, 0x05, 0x00, 0x00,
  218.         'I','N','C'+128,        2, 0xFE, 0x00, 0x40, 0x00,
  219.         'M','U','L'+128,        2, 0xF6, 0x04, 0x00, 0x00,
  220.         'N','E','G'+128,        2, 0xF6, 0x03, 0x00, 0x00,
  221.         'N','O','T'+128,        2, 0xF6, 0x02, 0x00, 0x00,
  222.         /* Type 2 - opcode */
  223.         'L','D','S'+128,        3, 0xC5, 0x00, 0x00, 0x00,
  224.         'L','E','A'+128,        3, 0x8D, 0x00, 0x00, 0x00,
  225.         'L','E','S'+128,        3, 0xC4, 0x00, 0x00, 0x00,
  226.         /* Type 4 - ACC/IMMED, REGIS,IMMED, INDEX,REGIS, XXX (Fn ='S') */
  227.         'A','D','C'+128,        4, 0x14, 0x80, 0x10, 0xF2,
  228.         'A','D','D'+128,        4, 0x04, 0x80, 0x00, 0xF0,
  229.         'S','U','B'+128,        4, 0x2C, 0x80, 0x28, 0xF5,
  230.         'S','B','B'+128,        4, 0x1C, 0x80, 0x18, 0xF3,
  231.         'C','M','P'+128,        4, 0x3C, 0x80, 0x38, 0xF7,
  232.         'A','N','D'+128,        4, 0x24, 0x80, 0x20, 0x04,
  233.         'O','R'+128,            4, 0x0C, 0x80, 0x08, 0x01,
  234.         'X','O','R'+128,        4, 0x34, 0x80, 0x30, 0x06,
  235.         'T','E','S','T'+128,    4, 0xA8, 0xF6, 0x84, 0x00,
  236.         /* Type 5 - MOV */
  237.         'M','O','V'+128,        5, 0x00, 0x00, 0x00, 0x00,    
  238.         /* Type 6 - single byte relative jumps */
  239.         'J','A'+128,            6, 0x77, 0x00, 0x00, 0x00,
  240.         'J','N','B','E'+128,    6, 0x77, 0x00, 0x00, 0x00,
  241.         'J','A','E'+128,        6, 0x73, 0x00, 0x00, 0x00,
  242.         'J','N','B'+128,        6, 0x73, 0x00, 0x00, 0x00,
  243.         'J','C'+128,            6, 0x72, 0x00, 0x00, 0x00,
  244.         'J','N','C'+128,        6, 0x73, 0x00, 0x00, 0x00,
  245.         'J','B'+128,            6, 0x72, 0x00, 0x00, 0x00,
  246.         'J','N','A','E'+128,    6, 0x72, 0x00, 0x00, 0x00,
  247.         'J','B','E'+128,        6, 0x76, 0x00, 0x00, 0x00,
  248.         'J','N','A'+128,        6, 0x76, 0x00, 0x00, 0x00,
  249.         'J','C','X','Z'+128,    6, 0xE3, 0x00, 0x00, 0x00,
  250.         'J','E'+128,            6, 0x74, 0x00, 0x00, 0x00,
  251.         'J','Z'+128,            6, 0x74, 0x00, 0x00, 0x00,
  252.         'J','G'+128,            6, 0x7F, 0x00, 0x00, 0x00,
  253.         'J','N','L','E'+128,    6, 0x7F, 0x00, 0x00, 0x00,
  254.         'J','G','E'+128,        6, 0x7D, 0x00, 0x00, 0x00,
  255.         'J','N','L'+128,        6, 0x7D, 0x00, 0x00, 0x00,
  256.         'J','L'+128,            6, 0x7C, 0x00, 0x00, 0x00,
  257.         'J','N','G','E'+128,    6, 0x7C, 0x00, 0x00, 0x00,
  258.         'J','L','E'+128,        6, 0x7E, 0x00, 0x00, 0x00,
  259.         'J','N','G'+128,        6, 0x7e, 0x00, 0x00, 0x00,
  260.         'J','N','E'+128,        6, 0x75, 0x00, 0x00, 0x00,
  261.         'J','N','Z'+128,        6, 0x75, 0x00, 0x00, 0x00,
  262.         'J','O'+128,            6, 0x70, 0x00, 0x00, 0x00,
  263.         'J','N','O'+128,        6, 0x71, 0x00, 0x00, 0x00,
  264.         'J','S'+128,            6, 0x78, 0x00, 0x00, 0x00,
  265.         'J','N','S'+128,        6, 0x79, 0x00, 0x00, 0x00,
  266.         'J','N','P'+128,        6, 0x7B, 0x00, 0x00, 0x00,
  267.         'J','P','O'+128,        6, 0x7B, 0x00, 0x00, 0x00,
  268.         'J','P'+128,            6, 0x7A, 0x00, 0x00, 0x00,
  269.         'J','P','E'+128,        6, 0x7A, 0x00, 0x00, 0x00,
  270.         'L','O','O','P'+128,    6, 0xE2, 0x00, 0x00, 0x00,
  271.         'L','O','O','P','E'+128,6, 0xE1, 0x00, 0x00, 0x00,
  272.         'L','O','O','P','Z'+128,6, 0xE1, 0x00, 0x00, 0x00,
  273.         'L','O','O','P','N','E'+128,6,0xE0,0x00,0x00,0x00,
  274.         'L','O','O','P','N','Z'+128,6,0xE0,0x00,0x00,0x00,
  275.         /* Type 7 - JMP/CALL */
  276.         'J','M','P'+128,        7, 0xE9, 0xEA, 0x04, 0x05,
  277.         'C','A','L','L'+128,    7, 0xE8, 0x9A, 0x02, 0x03,
  278.         /* Type 8 - RET/RETF */
  279.         'R','E','T'+128,        8, 0xC3, 0xC2, 0x00, 0x00,
  280.         'R','E','T','F'+128,    8, 0xCB, 0xCA, 0x00, 0x00,
  281.         /* Type 9 - SEGMENT, REGIS, MEMOP */
  282.         'P','O','P'+128,        9, 0x07, 0x58, 0x8F, 0x00,
  283.         'P','U','S','H'+128,    9, 0x06, 0x50, 0xFF, 0x06,
  284.         /* Type 10 - STRING instructions */
  285.         'C','M','P','S'+128,    10,0xA6, 0x00, 0x00, 0x00,
  286.         'L','O','D','S'+128,    10,0xAC, 0x00, 0x00, 0x00,
  287.         'M','O','V','S'+128,    10,0xA4, 0x00, 0x00, 0x00,
  288.         'S','C','A','S'+128,    10,0xAE, 0x00, 0x00, 0x00,
  289.         'S','T','O','S'+128,    10,0xAA, 0x00, 0x00, 0x00,
  290.         /* Type 11 - Shifts & Rotates */
  291.         'R','C','L'+128,        11,0xD0, 0x02, 0x00, 0x00,
  292.         'R','C','R'+128,        11,0xD0, 0x03, 0x00, 0x00,
  293.         'R','O','L'+128,        11,0xD0, 0x00, 0x00, 0x00,
  294.         'R','O','R'+128,        11,0xD0, 0x01, 0x00, 0x00,
  295.         'S','A','L'+128,        11,0xD0, 0x04, 0x00, 0x00,
  296.         'S','H','L'+128,        11,0xD0, 0x04, 0x00, 0x00,
  297.         'S','A','R'+128,        11,0xD0, 0x07, 0x00, 0x00,
  298.         'S','H','R'+128,        11,0xD0, 0x05, 0x00, 0x00,
  299.         /* Type 12 - INT */
  300.         'I','N','T'+128,        12, 0x00, 0x00, 0x00, 0x00,
  301.         /* Type 13 - ESC */
  302.         'E','S','C'+128,        13,0x00, 0x00, 0x00, 0x00,
  303.         /* Type 14 - IN/OUT */
  304.         'I','N'+128,            14,0xE4, 0xEC, 0x00, 0x00,
  305.         'O','U','T'+128,        14,0xE6, 0xEE, 0xFF, 0x00,
  306.         /* Type 15 - XCHG */
  307.         'X','C','H','G'+128,    15,0x86, 0x90, 0x00, 0x00,
  308.         /* Directives */
  309.         'E','Q','U'+128,        100, 0, 0, 0, 0,
  310.         'O','R','G'+128,        101, 0, 0, 0, 0,
  311.         'S','E','G'+128,        102, 0, 0, 0, 0,
  312.         'D','B'+128,            103, 0, 0, 0, 0,
  313.         'D','W'+128,            104, 0, 0, 0, 0,
  314.         'D','S'+128,            105, 0, 0, 0, 0,
  315.         'S','T','R'+128,        106, 0, 0, 0, 0,
  316.         'S','T','R','Z'+128,    106, 1, 0, 0, 0,
  317.         'S','T','R','H'+128,    106, 2, 0, 0, 0,
  318.         'P','U','B','L','I','C'+128,107,0,0,0,0,
  319.         'E','X','T','E','R','N'+128,108,0,0,0,0,
  320.         'P','A','G','E'+128,    120, 0, 0, 0, 0,
  321.         'T','I','T','L','E'+128,121, 0, 0, 0, 0,
  322.         'S','P','A','C','E'+128,122, 0, 0, 0, 0,
  323.         'L','I','S','T'+128,    123, 0, 0, 0, 0,
  324.         'N','O','L','I','S','T'+128,124,0,0,0,0,
  325.         0 }, *inst_ptr;
  326.  
  327. /* 8086 register table */
  328.     char *registers[] = {
  329.         "AL", "CL", "DL", "BL", "AH", "CH", "DH", "BH",
  330.         "AX", "CX", "DX", "BX", "SP", "BP", "SI", "DI",
  331.         "ES", "CS", "SS", "DS" };
  332.  
  333. /* Error messages */
  334.     char *error_text[] = {
  335.         "Phase error",
  336.         "Syntax error",
  337.         "Invalid instruction",
  338.         "Additional operands reqired",
  339.         "Constant value required",
  340.         "16 bit operand required",
  341.         "Illegal addressing mode",
  342.         "Illegal segment override",
  343.         "Illegal use of segment register",
  344.         "Invalid register operation",
  345.         "Invalid immediate expression",
  346.         "Invalid index register",
  347.         "Cannot preset register size",
  348.         "Unterminated character constant",
  349.         "Incompatible operand sizes",
  350.         "Size not known",
  351.         "Out of range",
  352.         "Undefined symbol",
  353.         "Duplicate sumbol",
  354.         "Symbol table overflow",
  355.         "Shift count must be CL or 1",
  356.         "Port must be DX or value",
  357.         "Accumulator required" };
  358.                 
  359. /* Input line buffer & holding areas */
  360.     char inline[LINSIZE+1], *input_ptr;
  361.     unsigned char label[SYMSIZE+1], instruction[80], operand[80];
  362.  
  363. /* Assembler symbol table & related routines */
  364.     char symbols[SYMBOLS][SYMSIZE+1];
  365.     int    svalue[SYMBOLS], scount = 0, sindex;
  366.     char sflags[SYMBOLS];
  367.  
  368. /* Assembler Segment holding areas */
  369.     unsigned active_seg, seg_pc[NUMSEG], seg_size[NUMSEG] = { 0 };
  370.  
  371. /* Global locations for operand results */
  372.     int type, length, value, xvalue;
  373.     int type1, value1, xvalue1;
  374.  
  375. /* Command line options flags */
  376.     char casf = 0, fulf = 0, symf = 0, quif = 0, ttyf = 0;
  377.  
  378. /* Global counters and misc variables */
  379.     char dir, title[50], list = 0;
  380.     unsigned pc, line, ocount, daddr;
  381.     unsigned pass = 0, error_flag = 0, error_count = 0;
  382.     unsigned ecount = 999, pcount = 1;
  383.  
  384.     FILE *asm_fp, *hex_fp, *lst_fp;
  385.  
  386. /*
  387.  * Open a filename with the appriopriate extension &
  388.  * report an error if not possible
  389.  */
  390. FILE *open_file(filename, extension, options)
  391.     char *filename, *extension, *options;
  392. {
  393.     char buffer[50], *ptr;
  394.  
  395.     for(ptr = buffer; *filename; ++ptr)
  396.         *ptr = *filename++;
  397.     *ptr++ = '.';
  398.     do
  399.         *ptr++ = *extension;
  400.     while(*extension++);
  401.  
  402.     return fopen(buffer, options);
  403. }
  404.  
  405. /*
  406.  * Main program
  407.  */
  408. main(argc, argv)
  409.     int argc;
  410.     char *argv[];
  411. {
  412.     int i;
  413.     char *ptr;
  414.  
  415.     if(argc < 2)
  416.         abort("\nUse: asm86 <filename> [+c +f +q +s +t]\n\nCopyright 1990-1994 Dave Dunfield\nAll rights reserved.\n");
  417.  
  418.     /* Parse for command line options */
  419.     for(i=2; i <argc; ++i) {
  420.         switch((argv[i][0]<<8)|toupper(argv[i][1])) {
  421.             case ('+'<<8)|'C' : casf = -1;    break;    /* Case sensitive */
  422.             case ('+'<<8)|'F' : fulf = -1;    break;    /* Full listing */
  423.             case ('+'<<8)|'S' : symf = -1;    break;    /* Symbol table */
  424.             case ('+'<<8)|'Q' : quif = -1;    break;    /* Quiet mode */
  425.             case ('+'<<8)|'T' : ttyf = -1;    break;    /* TTY output */
  426.             default:
  427.                 fprintf(stderr,"Unknown option: '%s'\n", argv[i]);
  428.                 exit(-1); } }
  429.  
  430.     strcpy(title, argv[1]);    /* Initial title is filename */
  431.  
  432.     /* Open input & output files */
  433.     asm_fp = open_file(title, "ASM", "rvq");
  434.     lst_fp = (ttyf) ? stdout : open_file(title, "LST", "wvq");
  435.     hex_fp = open_file(title, "COM", "wbvq");
  436.  
  437.     do {
  438.         if(!quif)
  439.             fprintf(stderr,"Pass %u... ", pass+1);
  440.         for(i = pc = line = active_seg = 0; i < NUMSEG; ++i)
  441.             seg_pc[i] = 0;
  442.         while(fgets(ptr = inline, LINSIZE, asm_fp)) {
  443.             error_flag = ocount = 0;
  444.             daddr = pc;
  445.             ++line;
  446.             if((*inline != '*')  && (*inline != ';')) {    /* Not a comment */
  447.                 i = 0;                        /* Parse label */
  448.                 while(!isterm(*ptr))
  449.                     label[i++] = chupper(*ptr++);
  450.                 label[i]=0;
  451.                 while(isspace(*ptr))
  452.                     ++ptr;
  453.                 i = 0;                        /* Parse instruction */
  454.                 while(!isterm(*ptr))
  455.                     instruction[i++] = toupper(*ptr++);
  456.                 instruction[i]=0;
  457.                 while(isspace(*ptr))
  458.                     ++ptr;
  459.                 i = 0;                        /* Parse operands */
  460.                 while(*ptr && (i < 79))
  461.                     operand[i++] = *ptr++;
  462.                 operand[i] = 0;
  463.                 if(*label && !pass)            /* Label this line */
  464.                     define(label, pc, active_seg);
  465.                 if(!lookup_inst())
  466.                     asmerr(2);
  467.                 input_ptr = operand;
  468.                 switch(*inst_ptr) {
  469. case 1 :    /* No operand */
  470.     i = 1;
  471.     do
  472.         instruction[ocount++] = inst_ptr[i];
  473.     while(inst_ptr[++i]);
  474.     break;
  475. case 2 :    /* DEC ... */
  476.     switch(oper3()) {
  477.         case REGIS :
  478.             test_register(value, 0x02);
  479.             if((value > 7) && inst_ptr[3]) {
  480.                 instruction[ocount++] = inst_ptr[3] | (value & 7);
  481.                 break; }
  482.         case INDEX :
  483.         case VALUE :
  484.             instruction[ocount++] = inst_ptr[1] | (length > 1);
  485.             write_ea(inst_ptr[2]);
  486.             break;
  487.         default:
  488.             asmerr(6); }
  489.     break;
  490. case 3 :    /* LDS ... */
  491.     switch(oper4()) {
  492.         case (REGIS<<8)+INDEX :
  493.         case (REGIS<<8)+VALUE :
  494.             test_register(value, 0x03);
  495.             direction();
  496.             instruction[ocount++] = inst_ptr[1];
  497.             write_ea(value1);
  498.             break;
  499.         default:
  500.             asmerr(6); }
  501.     break;
  502. case 4 :    /* ADC ... */
  503.     dir = 0;
  504.     switch(oper4()) {
  505.         case (REGIS<<8)+IMMED :        /* AX,#nn */
  506.             test_register(value, 0x02);
  507.             if(!(value & 0x07)) {
  508.                 instruction[ocount++] = inst_ptr[1] | (length > 1);
  509.                 write_value1();
  510.                 break; }
  511.         case (INDEX<<8)+IMMED :        /* [BX],#nn */
  512.         case (VALUE<<8)+IMMED :        /* SYM,#nn */
  513.             i = inst_ptr[2];
  514.             if(length > 1) {
  515.                 i |= 0x01;
  516.                 if((inst_ptr[4] & 0xF0) && (value1 <= 127) && (value1 >= -128)) {
  517.                     i |= 0x02;
  518.                     --length; } }
  519.             instruction[ocount++] = i;
  520.             write_ea(inst_ptr[4]);
  521.             write_value1();
  522.             break;
  523.         case (REGIS<<8)+REGIS :        /* BX,AX */
  524.             test_register(value, 0x02);
  525.             goto adc1;
  526.         case (REGIS<<8)+INDEX :        /* AX,[BX] */
  527.         case (REGIS<<8)+VALUE :        /* AX,nn */
  528.             direction();
  529.         case (INDEX<<8)+REGIS :        /* [BX],AX */
  530.         case (VALUE<<8)+REGIS :        /* 123,AX */
  531.             if(!inst_ptr[4])        /* Special case for "test" */
  532.                 dir = 0;
  533.         adc1:
  534.             test_register(value1, 0x02);
  535.             instruction[ocount++] = (inst_ptr[3] | (length > 1)) ^ dir;
  536.             write_ea(value1);
  537.             break;
  538.         default:
  539.             asmerr(6); }
  540.     break;
  541. case 5 :    /* MOV .. */
  542.     dir = 0;
  543.     switch(oper4()) {
  544.         case (REGIS<<8)+IMMED :
  545.             instruction[ocount++] = 0xB0 + (value & 0x07) + ((length > 1) * 0x08);
  546.             write_value1();
  547.             break;
  548.         case (VALUE<<8)+IMMED :
  549.         case (INDEX<<8)+IMMED :
  550.             instruction[ocount++] = 0xC6 + (length > 1);
  551.             write_ea(0);
  552.             write_value1();
  553.             break;
  554.         case (REGIS<<8)+INDEX :        /* AX,[BX] */
  555.         case (REGIS<<8)+VALUE :        /* AX,nn */
  556.             direction();
  557.         case (INDEX<<8)+REGIS :        /* [BX],AX */
  558.         case (VALUE<<8)+REGIS :        /* 123,AX */
  559.             if(value1 > 15) {        /* Segment register */
  560.                 instruction[ocount++] = 0x8C | dir;
  561.                 write_ea(value1); }
  562.             else if((type == VALUE) && !(value1 & 0x07)) {
  563.                 instruction[ocount++] = (0xA0 | length > 1) ^ dir ^ 0x02;
  564.                 instruction[ocount++] = value;
  565.                 instruction[ocount++] = value >> 8; }
  566.             else {
  567.                 instruction[ocount++] = (0x88 | (length > 1)) ^ dir;
  568.                 write_ea(value1); }
  569.             break;
  570.         case (REGIS<<8)+REGIS :        /* BX,AX */
  571.             if(value > 15) {
  572.                 test_register(value1, 0x03);
  573.                 direction();
  574.                 i = 0x8E; }
  575.             else if(value1 > 15) {
  576.                 test_register(value, 0x03);
  577.                 i = 0x8C; }
  578.             else
  579.                 i = 0x88 | (length > 1);
  580.             instruction[ocount++] = i;
  581.             write_ea(value1);
  582.             break;
  583.         default:
  584.             asmerr(6); }
  585.     break;
  586. case 6 :    /* short jumps */
  587.     if(oper2() == VALUE) {
  588.         value -= pc + 2;
  589.         if((value > 127) || (value < -128))
  590.             asmerr(16);
  591.         instruction[ocount++] = inst_ptr[1];
  592.         instruction[ocount++] = value; }
  593.     else
  594.         asmerr(6);
  595.     break;
  596. case 7 :    /* JMP and CALL */
  597.     i = 0;
  598.     type = oper2();
  599.     if(test_next(':')) {
  600.         if(type != VALUE)
  601.             asmerr(6);
  602.         i = -1;
  603.         value1 = value;
  604.         type = oper2(); }
  605.     switch(type) {
  606.         case VALUE :
  607.             if(length != 2) {
  608.                 if(i) {
  609.                     instruction[ocount++] = inst_ptr[2];
  610.                     instruction[ocount++] = value;
  611.                     instruction[ocount++] = value >> 8;
  612.                     length = 2;
  613.                     write_value1();
  614.                     break; }
  615.                 if(length == 1) {
  616.                     if(inst_ptr[1] != 0xE9)
  617.                         asmerr(6);
  618.                     value -= pc + 2;
  619.                     if((value > 127) || (value < -128))
  620.                         asmerr(16);
  621.                     instruction[ocount++] = 0xEB;
  622.                     instruction[ocount++] = value;
  623.                     break; }
  624.                 value -= pc + 3;
  625.                 instruction[ocount++] = inst_ptr[1];
  626.                 instruction[ocount++] = value;
  627.                 instruction[ocount++] = value >> 8;
  628.                 break; }
  629.         case REGIS :
  630.         case INDEX :
  631.             instruction[ocount++] = 0xFF;
  632.             write_ea(inst_ptr[i ? 4 : 3]);
  633.             break;
  634.         default:
  635.             asmerr(6); }
  636.     break;
  637. case 8 :    /* RET and RETF */
  638.     if((*input_ptr ==';') || !*input_ptr)
  639.         instruction[ocount++] = inst_ptr[1];
  640.     else {
  641.         get_constant(-1);
  642.         instruction[ocount++] = inst_ptr[2];
  643.         instruction[ocount++] = value;
  644.         instruction[ocount++] = value >> 8; }
  645.     break;
  646. case 9 :    /* PUSH and POP */
  647.     switch(oper3()) {
  648.         case REGIS :
  649.             if(length == 1)
  650.                 asmerr(5);
  651.             if(value > 15)
  652.                 instruction[ocount++] = inst_ptr[1] | ((value & 7) << 3);
  653.             else
  654.                 instruction[ocount++] = inst_ptr[2] | (value & 7);
  655.             break;
  656.         case VALUE :
  657.         case INDEX :
  658.             if(length == 1)
  659.                 asmerr(5);
  660.             instruction[ocount++] = inst_ptr[3];
  661.             write_ea(inst_ptr[4]);
  662.             break;
  663.         default:
  664.             asmerr(6); }
  665.     break;
  666. case 10 :    /* String instructions */
  667.     if(oper3() == VALUE)
  668.         instruction[ocount++] = inst_ptr[1] | (length > 1);
  669.     else
  670.         asmerr(6);
  671.     break;
  672. case 11 :    /* Shifts & Rotates */
  673.     if((type = oper2()) == IMMED)
  674.         asmerr(6);
  675.     if(!length)
  676.         asmerr(15);
  677.     i = length > 1;
  678.     if(!test_next(','))
  679.         asmerr(3);
  680.     direction();
  681.     type = oper2();
  682.     direction();
  683.     if(value1 != 1)
  684.         asmerr(20);
  685.     if(type1 == REGIS)
  686.         instruction[ocount++] = inst_ptr[1] | 2 | i;
  687.     else if(type1 == VALUE)
  688.         instruction[ocount++] = inst_ptr[1] | i;
  689.     else {
  690.         asmerr(20);
  691.         break; }
  692.     write_ea(inst_ptr[2]);
  693.     break;
  694. case 12 :    /* INT Statement */
  695.     get_constant(255);
  696.     if((value == 3) && (length < 2))
  697.         instruction[ocount++] = 0xCC;
  698.     else {
  699.         instruction[ocount++] = 0xCD;
  700.         instruction[ocount++] = value; }
  701.     break;
  702. case 13 :    /* ESC opcode */
  703.     switch(oper4()) {
  704.         case (VALUE<<8)+REGIS :
  705.             test_register(0x02);
  706.         case (VALUE<<8)+VALUE :
  707.         case (VALUE<<8)+INDEX :
  708.             direction();
  709.             instruction[ocount++] = 0xD8 | ((value1 >> 3) & 7);
  710.             write_ea(value1);
  711.             break;
  712.         default:
  713.             asmerr(6); }
  714.         break;
  715. case 14 :    /* IN and OUT */
  716.     type = oper2();
  717.     i = length;
  718.     if(!test_next(','))
  719.         asmerr(3);
  720.     direction();
  721.     type = oper2();
  722.     if(!inst_ptr[3]) {
  723.         direction();
  724.         length = i; }
  725.     if((type != REGIS) || (value & 0x17))
  726.         asmerr(22);
  727.     switch(type1) {
  728.         case VALUE :
  729.             if((value1 < 0 ) || (value1 > 255))
  730.                 asmerr(16);
  731.             instruction[ocount++] = inst_ptr[1] | (length > 1);
  732.             instruction[ocount++] = value1;
  733.             break;
  734.         case REGIS :
  735.             if(value1 != 10)
  736.                 asmerr(21);
  737.             instruction[ocount++] = inst_ptr[2] | (length > 1);
  738.             break;
  739.         default:
  740.             asmerr(21); }
  741.     break;
  742. case 15 :    /* XCHG */
  743.     switch(oper4()) {
  744.         case (REGIS<<8)+REGIS :
  745.             test_register(value, 2);
  746.             test_register(value1, 2);
  747.             if((value > 7) && !(value & 7))
  748.                 instruction[ocount++] = 0x90 | (value1 & 7);
  749.             else if((value1 > 7) && !(value1 & 7))
  750.                 instruction[ocount++] = 0x90 | (value & 7);
  751.             else
  752.                 goto doxchg;
  753.             break;
  754.         case (REGIS<<8)+INDEX :
  755.         case (REGIS<<8)+VALUE :
  756.             direction();
  757.         case (INDEX<<8)+REGIS :
  758.         case (VALUE<<8)+REGIS :
  759.             test_register(value1, 2);
  760.         doxchg:
  761.             instruction[ocount++] = inst_ptr[1] | (length > 1);
  762.             write_ea(value1);
  763.             break;
  764.         default:
  765.             asmerr(6); }
  766.     break;
  767. case 100 :    /* EQU statement */
  768.     if(pass)
  769.         daddr = get_constant(-1);
  770.     else {
  771.         svalue[sindex] = get_constant(-1);
  772.         if(error_flag)
  773.             show_error(error_flag); }
  774.     break;
  775. case 101 :    /* ORG statement */
  776.     daddr = pc = get_constant(-1);
  777.     break;
  778. case 102 :    /* SEG directive */
  779.     seg_pc[active_seg] = pc;
  780.     if(seg_size[active_seg] < pc)
  781.         seg_size[active_seg] = pc;
  782.     daddr = pc = seg_pc[active_seg = get_constant(NUMSEG-1) & (NUMSEG-1)];
  783.     break;
  784. case 103 :    /* DB statement */
  785.     do
  786.         instruction[ocount++] = get_constant(255);
  787.     while(test_next(','));
  788.     break;
  789. case 104 :    /* DW statement */
  790.     do {
  791.         get_constant(-1);
  792.         instruction[ocount++] = value;
  793.         instruction[ocount++] = value >> 8; }
  794.     while(test_next(','));
  795.     break;
  796. case 105 :    /* DS statement */
  797.     pc += get_constant(-1);
  798.     break;
  799. case 106 :    /* STR statement */
  800.     i = *input_ptr++;
  801.     while(*input_ptr != i) {
  802.         if(!*input_ptr) {
  803.             asmerr(13);
  804.             break; }
  805.         instruction[ocount++] = *input_ptr++; }
  806.     switch(inst_ptr[1]) {
  807.         case 1 :
  808.             instruction[ocount++] = 0;
  809.             break;
  810.         case 2 :
  811.             instruction[ocount-1] |= 0x80; }
  812.     break;
  813. case 107 :    /* PUBLIC statement */
  814.     if(pass) do {
  815.         ptr = input_ptr;
  816.         while(!isterm(i = *input_ptr))
  817.             *input_ptr++ = chupper(i);
  818.         *input_ptr++ = 0;
  819.         if(looksym(ptr, &value))
  820.             sflags[sindex] |= SPUB;
  821.         else
  822.             asmerr(17); }
  823.     while(i == ',');
  824.     break;
  825. case 108 :    /* EXTERN statement */
  826.     if(!pass) do {
  827.         ptr = input_ptr;
  828.         while(!isterm(i = *input_ptr))
  829.             *input_ptr++ = chupper(i);
  830.         *input_ptr++ = 0;
  831.         define(ptr, 0, SEXT | active_seg); }
  832.     while(i == ',');
  833.     break;
  834. case 120 :    /* PAGE directive */
  835.     ecount = 999;
  836.     break;
  837. case 121 :    /* TITLE directive */
  838.     strcpy(title, operand);
  839.     break;
  840. case 122 :    /* SPACE directive */
  841.     if(pass && fulf && !list) {
  842.         putc('\n', lst_fp);
  843.         ++ecount; }
  844.     break;
  845. case 123 :    /* LIST directive */
  846.     if(list)
  847.         --list;
  848.     break;
  849. case 124 :    /* NOLIST directive */
  850.     ++list;
  851. }
  852.             /* Check for out of PHASE errors & duplicated symbols */
  853.             if(*label && pass) {
  854.                 looksym(label, &i);
  855.                 if(sflags[sindex] & SDUP)
  856.                     error_flag = 18;
  857.                 else if(i != daddr) {
  858.                     show_error(0);
  859.                     exit(-1); } } }
  860.  
  861.         if(pass) {
  862.     /* Generate formatted output listing */
  863.             if((fulf && (*inst_ptr < 120) && !list) || error_flag) {
  864.                 if(++ecount > PAGSIZE)
  865.                     write_title();
  866.                 fprintf(lst_fp, "%04x ", daddr);
  867.                 for(i=0; i < 6; ++i)
  868.                     if(i < ocount)
  869.                         fprintf(lst_fp," %02x", instruction[i]);
  870.                     else
  871.                         fputs("   ", lst_fp);
  872.                 fprintf(lst_fp, " %c%5u  %s\n", (ocount <= 6) ? ' ' : '+', line, inline);
  873.                 if(error_flag)
  874.                     show_error(error_flag); }
  875.     /* Write the code file (just output binary for now) */
  876.             if(ocount)
  877.                 fwrite(instruction, ocount, hex_fp); }
  878.         pc += ocount; /* For now till write code */
  879.         }
  880.     if(seg_size[active_seg] < pc)
  881.         seg_size[active_seg] = pc;
  882.     rewind(asm_fp); }
  883.     while(++pass < 2);
  884.  
  885.     if(error_count)
  886.         fprintf(lst_fp,"\n %u error(s) occurred in this assembly.\n",error_count);
  887.  
  888.     if(!quif)
  889.         fprintf(stderr,"%u error(s).\n",error_count);
  890.  
  891. /* display the symbol table */
  892.     if(symf) {
  893.         for(i=0; i < scount; ++i) {
  894.             daddr=i;
  895.             for(pc=i+1; pc < scount; ++pc)
  896.                 if(strcmp(symbols[daddr], symbols[pc]) > 0)
  897.                     daddr = pc;
  898.             pc = svalue[i];
  899.             strcpy(inline, symbols[i]);
  900.             svalue[i] = svalue[daddr];
  901.             strcpy(symbols[i], symbols[daddr]);
  902.             svalue[daddr] = pc;
  903.             strcpy(symbols[daddr], inline); }
  904.         write_title();
  905.         fprintf(lst_fp,"\nSYMBOL TABLE:\n\n");
  906.         for(i=0; i < scount;) {
  907.             fprintf(lst_fp,"%-9s-%04x", &symbols[i][0], svalue[i]);
  908.             ++i;
  909.             fputs((i%8) ? "  " : "\n", lst_fp); }
  910.         if(i%8) fprintf(lst_fp,"\n"); }
  911.  
  912.     fclose(asm_fp);
  913.     fclose(hex_fp);
  914.     fclose(lst_fp);
  915. }
  916.  
  917. /* output title */
  918. write_title()
  919. {
  920.     if(pcount > 1)
  921.         putc('\f',lst_fp);
  922.     ecount=0;
  923.     fprintf(lst_fp,"MICRO 8086 ASSEMBLER: %-80s   PAGE: %u\n\n",title,pcount);
  924.     ++pcount;
  925. }
  926.  
  927. /*
  928.  * Reverse operands, setting diretion flag
  929.  */
  930. direction()
  931. {
  932.     int i;
  933.  
  934.     i = type;    type = type1;    type1 = i;
  935.     i = value;    value = value1;    value1 = i;
  936.     i = xvalue; xvalue=xvalue1; xvalue1 = i;
  937.     dir = 0x02;
  938. }
  939.  
  940. /*
  941.  * Test a register for valid ranges
  942.  */
  943. test_register(reg, flags)
  944.     int reg;
  945.     char flags;
  946. {
  947.     if(pass) {
  948.         if((flags & 0x01) && (reg < 8))        /* No 8 bit registers */
  949.             asmerr(5);
  950.         if((flags & 0x02) && (reg > 15))    /* No segment registers */
  951.             asmerr(8); }
  952. }
  953.  
  954. /*
  955.  * Writes the value of value1
  956.  */
  957. write_value1()
  958. {
  959.     instruction[ocount++] = value1;
  960.     if(length > 1)
  961.         instruction[ocount++] = value1 >> 8;
  962. }
  963.  
  964. /*
  965.  * Build the EA value from parsed data
  966.  */
  967. write_ea(xxx)
  968.     int xxx;
  969. {
  970.     int dflag;
  971.  
  972.     dflag = 0;
  973.     xxx = (xxx & 7) << 3;
  974.     switch(type) {
  975.         case REGIS :    /* Register reference */
  976.             xxx |= 0xC0 + (value & 7);
  977.             break;
  978.         case VALUE :    /* Direct memory reference */
  979.             xxx |= 6;
  980.             dflag = 2;
  981.             break;
  982.         case INDEX :    /* Indexed addressing mode */
  983.             if((value > 127) || (value < -128)) {
  984.                 xxx |= 0x80;    /* 16 bit displacement */
  985.                 dflag = 2; }
  986.             else if(value || (xvalue == 6)) {
  987.                 xxx |= 0x40;    /* 8 bit displacement */
  988.                 dflag = 1; }
  989.             xxx |= xvalue;
  990.             break;
  991.         default:
  992.             asmerr(6); }
  993.         instruction[ocount++] = xxx;
  994.         if(dflag)
  995.             instruction[ocount++] = value;
  996.         if(dflag > 1)
  997.             instruction[ocount++] = value >> 8;
  998.     return dflag+1;
  999. }
  1000.  
  1001. /*
  1002.  * Get a constant value
  1003.  */
  1004. get_constant(limit)
  1005.     unsigned limit;
  1006. {
  1007.     if(oper2() != VALUE)
  1008.         asmerr(4);
  1009.     if(value > limit) {
  1010.         value = 0;
  1011.         asmerr(16); }
  1012.     return value;
  1013. }
  1014.  
  1015. /*
  1016.  * Get two complete operands with error checking
  1017.  */
  1018. oper4()
  1019. {
  1020.     int l, v, x;
  1021.  
  1022.     type = oper2();
  1023.     l = length;
  1024.     v = value;
  1025.     x = xvalue;
  1026.     if(!test_next(','))
  1027.         asmerr(3);
  1028.     type1 = oper2();
  1029.     if(!isterm(*input_ptr))
  1030.         asmerr(1);
  1031.  
  1032.     /* Make sure that the lengths are compatible */
  1033.     if(!(length || l))
  1034.         asmerr(15);
  1035.     else if(length && l && (length != l))
  1036.         asmerr(14);
  1037.     else if(l)
  1038.         length = l;
  1039.  
  1040.     value1 = value; value = v;
  1041.     xvalue1 = xvalue; xvalue = x;
  1042.  
  1043.     return (type << 8) + type1;
  1044. }
  1045.  
  1046. /*
  1047.  * Get a one complete operand with error checking
  1048.  */
  1049. oper3()
  1050. {
  1051.     type = oper2();
  1052.     if(!isterm(*input_ptr))
  1053.         asmerr(1);
  1054.     if(!length)
  1055.         asmerr(15);
  1056.     return type;
  1057. }
  1058.  
  1059. /*
  1060.  * Get and evaluate a single operand expression
  1061.  */
  1062. oper2()
  1063. {
  1064.     int i, j;
  1065.     char o, immed;
  1066.  
  1067.     immed = test_next('#');
  1068.  
  1069.     if(isterm(*input_ptr))
  1070.         asmerr(3);
  1071.  
  1072.     if(oper1(&value, &length) == REGIS) {    /* Simple register */
  1073.         if((value > 15) && (*input_ptr == ':')) {
  1074.             ++input_ptr;
  1075.             instruction[ocount++] = 0x26 | ((value & 3) << 3);
  1076.             i = oper1(&value, &length);
  1077.             if((i != VALUE) && (i != INDEX))
  1078.                 asmerr(7); }
  1079.         else {
  1080.             if(!isterm(*input_ptr))
  1081.                 asmerr(9);
  1082.             return REGIS; } }
  1083.  
  1084.     /* A value of a memory reference */
  1085.     while(*input_ptr && !isterm(*input_ptr)) {
  1086.         if(isoper(o = *input_ptr)) {
  1087.             ++input_ptr;
  1088.             if(oper1(&i, &j) == REGIS)
  1089.                 asmerr(9);
  1090.             if(length && j && (length != j))
  1091.                 asmerr(14);
  1092.             if(j)
  1093.                 length = j;
  1094.             switch(o) {
  1095.                 case '+' : value += i;    break;
  1096.                 case '-' : value -= i;    break;
  1097.                 case '*' : value *= i;    break;
  1098.                 case '/' : value /= i;    break;
  1099.                 case '%' : value %= i;    break;
  1100.                 case '&' : value &= i;    break;
  1101.                 case '|' : value |= i;    break;
  1102.                 case '^' : value ^= i;    break;
  1103.                 case '<' : value <<=i;    break;
  1104.                 case '>' : value >>=i; } }
  1105.         else if(o == '[') {                /* Indexing operation */
  1106.             ++input_ptr;
  1107.             xvalue = test_index(255);
  1108.             if(test_next('+'))            /* Two registers */
  1109.                 xvalue = test_index(xvalue);
  1110.             if(!test_next(']'))
  1111.                 asmerr(1);
  1112.             if(immed)
  1113.                 asmerr(10);
  1114.             return INDEX; }
  1115.         else {
  1116.             asmerr(1);
  1117.             break; } }
  1118.  
  1119.     return immed ? IMMED : VALUE;
  1120. }
  1121.  
  1122. /*
  1123.  * Scan for a single operand
  1124.  */
  1125. oper1(val, len)
  1126.     int *val, *len;
  1127. {
  1128.     unsigned base, v, l, v1, l1;
  1129.     char symbol[SYMSIZE+1], c;
  1130.  
  1131.     v = l = 0;
  1132.     for(;;) switch(*input_ptr++) {
  1133.         case '(' :            /* Nested expression */
  1134.             v1 = value;
  1135.             l1 = length;
  1136.             if(oper2() != VALUE)
  1137.                 asmerr(4);
  1138.             v = value;
  1139.             l = length;
  1140.             value = v1;
  1141.             length = l1;
  1142.             if(!test_next(')'))
  1143.                 asmerr(1);
  1144.             goto retval;
  1145.         case '<' :            /* Force 8 bit value */
  1146.             l = 1;
  1147.             break;
  1148.         case '>' :            /* Force 16 bit value */
  1149.             l = 2;
  1150.             break;
  1151.         case '-' :            /* Unary minus */
  1152.             base = oper1(&v, &l);
  1153.             *val = -v;
  1154.             *len = l;
  1155.             return base;
  1156.         case '=' :            /* Swap high and low */
  1157.             base = oper1(&v, &l);
  1158.             *val = (v<<8)+(v>>8);
  1159.             *len = l;
  1160.             return base;
  1161.         case '$' :            /* Hexidecimal number */
  1162.             base = 16;
  1163.             goto getn;
  1164.         case '%' :            /* Binary number */
  1165.             base = 2;
  1166.             goto getn;
  1167.         case '@' :            /* Octal number */
  1168.             base = 8;
  1169.             goto getn;
  1170.         case '0' :            /* Decimal number */
  1171.         case '1' :
  1172.         case '2' :
  1173.         case '3' :
  1174.         case '4' :
  1175.         case '5' :
  1176.         case '6' :
  1177.         case '7' :
  1178.         case '8' :
  1179.         case '9' :
  1180.             base = 10;
  1181.             --input_ptr;
  1182.         getn:
  1183.             for(;;) {
  1184.                 if(isdigit(c = *input_ptr))        /* convert numeric digits */
  1185.                     c -= '0';
  1186.                 else if(c >= 'a')                /* convert lower case alphabetics */
  1187.                     c -= ('a' - 10);
  1188.                 else if(c >= 'A')                /* convert upper case alphabetics */
  1189.                     c -= ('A' - 10);
  1190.                 else                            /* not a valid "digit" */
  1191.                     break;
  1192.                 if(c >= base)                    /* outside of base */
  1193.                     break;
  1194.                 v = (v * base) + c;                /* include in total */
  1195.                 ++input_ptr; }
  1196.             goto retval;
  1197.         case '\'' :            /* Quoted value */
  1198.             while((c = *input_ptr) && (c != '\'')) {
  1199.                 ++input_ptr;
  1200.                 v = (v << 8) + c; }
  1201.             if(*input_ptr)
  1202.                 ++input_ptr;
  1203.             else
  1204.                 asmerr(13);
  1205.             goto retval;
  1206.         case '*' :            /* Program counter */
  1207.             v = pc;
  1208.             goto retval;
  1209.         default :            /* Symbol value */
  1210.             --input_ptr;
  1211.             while(issymbol(c = *input_ptr)) {
  1212.                 ++input_ptr;
  1213.                 symbol[v++] = chupper(c); }
  1214.             symbol[v] = 0;
  1215.             if(v) {
  1216.                 for(v = 0; v < NUMREG; ++v)
  1217.                     if(!strcmp(symbol, registers[v])) {
  1218.                         if(l)
  1219.                             asmerr(12);
  1220.                         *val = v;
  1221.                         *len = (v > 7) + 1;
  1222.                         return REGIS; }
  1223.                 if(!looksym(symbol, &v))
  1224.                     asmerr(17); }
  1225.         retval:
  1226.             *val = v;
  1227.             *len = l;
  1228.             return VALUE; }
  1229. }
  1230.  
  1231. /*
  1232.  * Test the next character in the stream
  1233.  */
  1234. test_next(c)
  1235.     char c;
  1236. {
  1237.     if(*input_ptr == c) {
  1238.         ++input_ptr;
  1239.         return -1; }
  1240.     return 0;
  1241. }
  1242.  
  1243. /*
  1244.  * Convert character to upper case if NOT case sensitive
  1245.  */
  1246. chupper(c)
  1247.     char c;
  1248. {
  1249.     return casf ? c : ((c >= 'a') && (c <= 'z')) ? c - ('a'-'A') : c;
  1250. }
  1251.  
  1252. /*
  1253.  * Test for a valid INDEX register combination
  1254.  */
  1255. test_index(reg)
  1256.     int reg;
  1257. {
  1258.     int v, l;
  1259.  
  1260.     if(oper1(&v, &l) == VALUE)    /* Invalid, force an error */
  1261.         reg = 0;
  1262.     switch((reg << 8) + v) {
  1263.         case 0xFF0B :    /* [BX] */
  1264.             return 7;
  1265.         case 0xFF0D :    /* [BP] */
  1266.             return 6;
  1267.         case 0xFF0E :    /* [SI] */
  1268.             return 4;
  1269.         case 0xFF0F :    /* [DI] */
  1270.             return 5;
  1271.         case 0x070E :    /* [BX+SI] */
  1272.         case 0x040B :    /* [SI+BX] */
  1273.             return 0;
  1274.         case 0x070F :    /* [BX+DI] */
  1275.         case 0x050B :    /* [DI+BX] */
  1276.             return 1;
  1277.         case 0x060E :    /* [BP+SI] */
  1278.         case 0x040D :    /* [SI+BP] */
  1279.             return 2;
  1280.         case 0x060F :    /* [BP+DI] */
  1281.         case 0x050D :    /* [DI+BP] */
  1282.             return 3;
  1283.         default:
  1284.             asmerr(11); }
  1285. }
  1286.  
  1287. /*
  1288.  * Report an assembly error
  1289.  */
  1290. asmerr(errno)
  1291.     int errno;
  1292. {
  1293.     if(!error_flag)
  1294.         error_flag = errno;
  1295. }
  1296.  
  1297. /*
  1298.  * Display an error
  1299.  */
  1300. show_error(errno)
  1301.     int errno;
  1302. {
  1303.     fprintf(lst_fp,"** Error %u in line %u : %s\n", errno, line, error_text[errno]);
  1304.     ++error_count;
  1305. }
  1306.  
  1307. /*
  1308.  * Test for a valid symbol name character
  1309.  */
  1310. issymbol(c)
  1311.     char c;
  1312. {
  1313.     return isalpha(c) || isdigit(c) || (c == '_') || (c == '?');
  1314. }
  1315.  
  1316. /*
  1317.  * Test for a valid operation character
  1318.  */
  1319. isoper(c)
  1320.     char c;
  1321. {
  1322.     char d, *ptr;
  1323.  
  1324.     ptr = "+-*/%&|^<>";        /* Table of valid operators */
  1325.     while(d = *ptr++)
  1326.         if(c == d)
  1327.             return -1;
  1328.  
  1329.     return 0;
  1330. }
  1331.  
  1332. /*
  1333.  * Test for terminater character
  1334.  */
  1335. isterm(c)
  1336.     char c;
  1337. {
  1338.     switch(c) {
  1339.         case 0 :
  1340.         case ' ' :
  1341.         case '\t':
  1342.         case ',' :
  1343.         case ':' :
  1344.         case ')' :
  1345.             return 1; }
  1346.     return 0;
  1347. }
  1348.  
  1349. /*
  1350.  * Define a symbol
  1351.  */
  1352. define(name, value, flags)
  1353.     char *name;
  1354.     int value, flags;
  1355. {
  1356.     int i;
  1357.  
  1358.     if(looksym(label, &i))
  1359.         sflags[sindex] |= SDUP;
  1360.     else {
  1361.         if(scount >= SYMBOLS) {        /* Symbol table overflow */
  1362.             show_error(19);
  1363.             exit(-1); }
  1364.         strcpy(symbols[sindex = scount], name);
  1365.         svalue[scount] = value;
  1366.         sflags[scount++] = flags; }
  1367. }
  1368.  
  1369. /*
  1370.  * Lookup a symbol in the symbol table
  1371.  */
  1372. looksym(symbol, v)
  1373.     char *symbol;
  1374.     int *v;
  1375. {
  1376.     int i;
  1377.  
  1378.     for(i=0; i < scount; ++i)
  1379.         if(!strcmp(symbol, symbols[i])) {
  1380.             *v = svalue[sindex = i];
  1381.             return -1; }
  1382.     return 0;
  1383. }
  1384.  
  1385. /*
  1386.  * Lookup instruction in table
  1387.  */
  1388. lookup_inst()
  1389. {
  1390.     char *ptr1, *ptr2;
  1391.  
  1392.     ptr1 = inst_table;
  1393.     while(*ptr1) {
  1394.         ptr2 = instruction;
  1395.         while(*ptr1 == *ptr2) {
  1396.             ++ptr1;
  1397.             ++ptr2; }
  1398.         if(((*ptr1 & 0x7f) == *ptr2) && isterm(*++ptr2)) {
  1399.             inst_ptr = ptr1 + 1;
  1400.             return 1; }
  1401.         while(!(*ptr1++ & 0x80));
  1402.         ptr1 += IDATSIZ; }
  1403.  
  1404.     inst_ptr = ptr1;
  1405.     return 0;
  1406. }
  1407.